'''
Created on 03/05/2011

@author: Adam
'''
import logging
import math
from google.appengine.ext import db
from google.appengine.api import memcache
import aetycoon as dbExt

class FuelType(db.Model):
	name = db.StringProperty(required=True)
	searchableName = dbExt.LowerCaseProperty(name)
	updated = db.DateTimeProperty(required=True, auto_now=True)
	created = db.DateTimeProperty(required=True, auto_now_add=True)
	mass = db.IntegerProperty(required=True)
	volume = db.FloatProperty(required=True)
	basePrice = db.IntegerProperty(required=True)
	iconId = db.IntegerProperty(required=True)
	
	@classmethod
	def getByEveId(cls, eveId):
		return FuelType.get_by_key_name(str(eveId))
	
	@classmethod
	def updateOrAddFromJson(cls, json):
		eveId = str(json['typeID'])
		name = json['typeName']
		mass = int(json['mass'])
		volume = float(json['volume'])
		basePrice = int(json['basePrice'])
		iconId = int(json['iconID'])
		
		changed = False
		fuel = FuelType.get_or_insert(eveId,
					name=name,
					mass=mass,
					volume=volume,
					basePrice=basePrice,
					iconId=iconId)
		if name != fuel.name:
			fuel.name = name
			changed = True
		if mass != fuel.mass:
			fuel.mass = mass
			changed = True
		if volume != fuel.volume:
			fuel.volume = volume
			changed = True
		if basePrice != fuel.basePrice:
			fuel.basePrice = basePrice
			changed = True
		if iconId != fuel.iconId:
			fuel.iconId = iconId
			changed = True
		return (fuel, changed)
	
	
class Type(db.Model):
	name = db.StringProperty(required=True)
	searchableName = dbExt.LowerCaseProperty(name)
	updated = db.DateTimeProperty(required=True, auto_now=True)
	created = db.DateTimeProperty(required=True, auto_now_add=True)
	mass = db.IntegerProperty()
	volume = db.FloatProperty()
	fuelCapacity = db.IntegerProperty()
	strontCapacity = db.IntegerProperty()
	basePrice = db.IntegerProperty()
	powerOutput = db.IntegerProperty()
	cpuOutput = db.IntegerProperty()
	anchoringDelay = db.IntegerProperty()
	unanchoringDelay = db.IntegerProperty()
	onliningDelay = db.IntegerProperty()
	posControlTowerPeriod = db.IntegerProperty()
	siloCapacityBonus = db.FloatProperty()
	size = dbExt.ChoiceProperty([(0, None), (1,'Small'), (2,'Medium'), (3,'Large')])
	
	optimalCyclesCache = {}
	
	def optimalCycles(self, sec=0.0, sov=False):
		cacheKey = '%s-%.1f-%s' % (str(self.key()), sec, sov)

		cycles = memcache.get(cacheKey)
		if cycles is None:
			fuels = self.fuel
			fuels.filter('purpose < ', Fuel.purpose.REINFORCE)
			results = fuels.fetch(100)
			totalVolume = 0.0;
			for fuel in results:
				totalVolume += fuel.reqCubic(sec=sec, sov=sov)
			cycles = int(math.floor(float(self.fuelCapacity) / totalVolume))
			
			memcache.set(cacheKey, cycles, time=600)
		return cycles
	
	def optimalDuration(self, sec=0.0, sov=False):
		cycles = self.optimalCycles(sec=sec, sov=sov)
		return cycles * self.posControlTowerPeriod
		
	@classmethod
	def getByEveId(cls, eveId):
		return Type.get_by_key_name(str(eveId))

	def updateTypeAttributesFromJson(self, records):
		changed = False
		for attribute in records:
			if attribute['valueInt'] is not None:
				intValue = int(attribute['valueInt'])
			if attribute['valueFloat'] is not None:
				floatValue = float(attribute['valueFloat'])
			
			if attribute['attributeName'] == 'capacitySecondary':
				intFloatValue = int(round(floatValue))
				if intFloatValue != self.strontCapacity:
					self.strontCapacity = intFloatValue
					changed = True
			if attribute['attributeName'] == 'powerOutput':
				if intValue != self.powerOutput:
					self.powerOutput = intValue
					changed = True
			if attribute['attributeName'] == 'cpuOutput':
				if intValue != self.cpuOutput:
					self.cpuOutput = intValue
					changed = True
			if attribute['attributeName'] == 'anchoringDelay':
				intValue = intValue / 1000
				if intValue != self.anchoringDelay:
					self.anchoringDelay = intValue
					changed = True
			if attribute['attributeName'] == 'unanchoringDelay':
				intFloatValue = int(round(floatValue))
				intFloatValue = intFloatValue / 1000
				if intValue != self.unanchoringDelay:
					self.unanchoringDelay = intFloatValue
					changed = True
			if attribute['attributeName'] == 'onliningDelay':
				intValue = intValue / 1000
				if intValue != self.onliningDelay:
					self.onliningDelay = intValue
					changed = True
			if attribute['attributeName'] == 'posControlTowerPeriod':
				intValue = intValue / 1000
				if intValue != self.posControlTowerPeriod:
					self.posControlTowerPeriod = intValue
					changed = True
			if attribute['attributeName'] == 'siloCapacityBonus':
				if intValue != self.siloCapacityBonus:
					self.siloCapacityBonus = intValue
					changed = True
			if attribute['attributeName'] == 'controlTowerSize':
				if intValue == Type.size.LARGE:
					intValue = 'Large'
				if intValue == Type.size.MEDIUM:
					intValue = 'Medium'
				if intValue == Type.size.SMALL:
					intValue = 'Small'
				if intValue != self.size:
					self.size = intValue
					changed = True
		return changed
				
	
	@classmethod
	def updateOrAddFromJson(cls, json):
		eveId = str(json['typeID'])
		name = json['typeName']
		mass = int(json['mass'])
		volume = float(json['volume'])
		basePrice = int(json['basePrice'])
		capacity = int(json['capacity'])

		changed = False
		type = Type.get_or_insert(eveId,
					name=name)
		if name != type.name:
			type.name = name
			changed = True
		if mass != type.mass:
			type.mass = mass
			changed = True
		if volume != type.volume:
			type.volume = volume
			changed = True
		if basePrice != type.basePrice:
			type.basePrice = basePrice
			changed = True
		if capacity != type.fuelCapacity:
			type.fuelCapacity = capacity
			changed = True
		return (type, changed)

class Fuel(db.Model):
	towerType = db.ReferenceProperty(reference_class=Type, collection_name='fuel', required=True)
	fuelType = db.ReferenceProperty(reference_class=FuelType, collection_name='usages', required=True)
	purpose = dbExt.ChoiceProperty([(0,None), (1,'Online'), (2,'Power'), (3,'CPU'), (4,'Reinforce')])
	quantity = db.IntegerProperty()
	minSecurityLevel = db.FloatProperty()
	
	def reqQuantity(self, sec=0.0, sov=False):
		quantity = 0
		if self.minSecurityLevel is None:
			quantity = self.quantity
		if sec > self.minSecurityLevel:
			quantity = self.quantity
		if sov:
			quantity = int(math.ceil(float(quantity) * 0.75))
		return quantity
	
	def reqCubic(self, sec=0.0, sov=False):
		quantity = self.reqQuantity(sec=sec, sov=sov)
		return quantity * self.fuelType.volume

	@classmethod
	def getByEveId(cls, towerTypeId, fuelTypeId):
		return Fuel.get_by_key_name(str(towerTypeId) + ' ' + str(fuelTypeId))

	@classmethod
	def updateOrAddFromJson(cls, json):
		towerTypeId = str(json['controlTowerTypeID'])
		towerType = Type.getByEveId(towerTypeId)
		fuelTypeId = str(json['resourceTypeID'])
		fuelType = FuelType.getByEveId(fuelTypeId)
		purpose = str(json['purposeText'])
		quantity = int(json['quantity'])
		minSecurityLevel = json['minSecurityLevel']
		if minSecurityLevel is not None:
			minSecurityLevel = float(minSecurityLevel)
		
		changed = False
		fuel = Fuel.get_or_insert(towerTypeId + ' ' + fuelTypeId,
					towerType=towerType,
					fuelType=fuelType)
		if purpose != fuel.purpose:
			fuel.purpose = purpose
			changed = True
		if quantity != fuel.quantity:
			fuel.quantity = quantity
			changed = True
		if minSecurityLevel != fuel.minSecurityLevel:
			fuel.minSecurityLevel = minSecurityLevel
			changed = True
		return (fuel, changed)
